Part 1: RNA

Load RNA samples

Out of 30 samples, we selected 17 for this study. These are the normal tissue samples form the control, the UVA and the UVA+SFN treatment groups. normal tissue samples from the UVB_UA groups as well as tumor samples were excluded from this analysis. Additionally, one of the control samples at Week 2 (baseline) was removed after outlier analysis.
7,219 genes with zero counts in > 80% (> 13 out of 18) of samples were removed. 17,202 out of 24,421 genes were left.

[1] 7219
[1] 17202

Transcripts per kilobase million (TPM) normalization

Next, we noramized the counts. To convert number of hits to the relative abundane of genes in each sample, we used transcripts per kilobase million (TPM) normalization, which is as following for the j-th sample:
1. normilize for gene length: a[i, j] = 1,000*count[i, j]/gene[i, j] length(bp)
2. normalize for seq depth (i.e. total count): a(i, j)/sum(a[, j])
3. multiply by one million
A very good comparison of normalization techniques can be found at the following video:
RPKM, FPKM and TPM, clearly explained

After the normalization, each sample’s total is 1M:

02w_CON_0 02w_SFN_0 02w_SFN_1 02w_UVB_0 02w_UVB_1 15w_CON_0 15w_CON_1 15w_SFN_0 
    1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06 
15w_SFN_1 15w_UVB_0 15w_UVB_1 25w_CON_0 25w_CON_1 25w_SFN_0 25w_SFN_1 25w_UVB_0 
    1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06 
25w_UVB_1 
    1e+06 

Top 100 most abundant RNA molecules

# Separate top 100 abundant genes
tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[(nrow(tpm) - 99):nrow(tpm)]])

tmp <- melt.data.table(data = tmp,
                       id.vars = 1:2,
                       measure.vars = 3:ncol(tmp),
                       variable.name = "Sample",
                       value.name = "TPM")

tmp$Week <- substr(x = tmp$Sample,
                   start = 1,
                   stop = 3)
tmp$Week <- factor(tmp$Week,
                   levels = unique(tmp$Week))


tmp$Treatment <- substr(x = tmp$Sample,
                        start = 5,
                        stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
                        levels = c("CON", 
                                   "UVB",
                                   "SFN"))

tmp$Replica <- substr(x = tmp$Sample,
                      start = 9,
                      stop = 9)
tmp$Replica <- factor(tmp$Replica,
                      levels = 0:1)

# Plot top 100 abundant genes
p2 <- ggplot(tmp,
             aes(x = TPM,
                 y = Geneid,
                 fill = Treatment,
                 shape = Week)) +
  # facet_wrap(~ Sex, nrow = 1) +
  geom_point(size = 3,
             alpha = 0.5) +
  geom_vline(xintercept = 1,
             linetype = "dashed")
ggplotly(p2)

Bottom 100 least abundant RNA molecules

tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[1:100]])

tmp <- melt.data.table(data = tmp,
                       id.vars = 1:2,
                       measure.vars = 3:ncol(tmp),
                       variable.name = "Sample",
                       value.name = "TPM")

tmp$Week <- substr(x = tmp$Sample,
                   start = 1,
                   stop = 3)
tmp$Week <- factor(tmp$Week,
                   levels = unique(tmp$Week))


tmp$Treatment <- substr(x = tmp$Sample,
                        start = 5,
                        stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
                        levels = c("CON", 
                                   "UVB",
                                   "SFN"))

tmp$Replica <- substr(x = tmp$Sample,
                      start = 9,
                      stop = 9)
tmp$Replica <- factor(tmp$Replica,
                      levels = 0:1)

# Plot top 100 abundant genes
p3 <- ggplot(tmp,
             aes(x = TPM,
                 y = Geneid,
                 fill = Treatment,
                 shape = Week)) +
  # facet_wrap(~ Sex, nrow = 1) +
  geom_point(size = 3,
             alpha = 0.5) +
  geom_vline(xintercept = 1,
             linetype = "dashed")
ggplotly(p3)

Meta data

dmeta <- data.table(Sample = colnames(dt1)[-c(1:2)])

dmeta$time <- substr(x = dmeta$Sample,
                     start = 1,
                     stop = 3)
dmeta$time <- factor(dmeta$time,
                     levels = c("02w",
                                "15w",
                                "25w"))
dmeta$Week <- factor(dmeta$time,
                     levels = c("02w",
                                "15w",
                                "25w"),
                     labels = c("Week 2",
                                "Week 15",
                                "Week 25"))

dmeta$trt <- substr(x = dmeta$Sample,
                    start = 5,
                    stop = 7)
dmeta$trt <- factor(dmeta$trt,
                    levels = c("CON", 
                               "UVB",
                               "SFN"))
dmeta$Treatment <- factor(dmeta$trt,
                          levels = c("CON", 
                                     "UVB",
                                     "SFN"),
                          labels = c("Negative Control",
                                     "Positive Control (UVB)",
                                     "Sulforaphane (SFN)"))

dmeta$Replica <- substr(x = dmeta$Sample,
                        start = 9,
                        stop = 9)
dmeta$Replica <- factor(dmeta$Replica,
                        levels = 0:1)

datatable(dmeta,
          options = list(pageLength = nrow(dmeta)))

PCA of TPM

NOTE: the distributions are skewed. To make them symmetric, log transformation is often applied. However, there is an issue of zeros. In this instance, we added a small values lambda[i] equal to 1/10 of the smallest non-zero value of i-th gene.

dm.tpm <- as.matrix(tpm[, -c(1:2), with = FALSE])
rownames(dm.tpm) <- tpm$Geneid

# # Remove 02w_CON_1 sample and redo PCA
# dm.tpm <- dm.tpm[, colnames(dm.tpm) != "02w_CON_1"]
# dmeta <- dmeta[dmeta$Sample != "02w_CON_1", ]

# Add lambdas to all values, then take a log
dm.ltpm <- t(apply(X = dm.tpm,
                      MARGIN = 1,
                      FUN = function(a) {
                        lambda <- min(a[a > 0])/10
                        log(a + lambda)
                      }))

# PCA----
m1 <- prcomp(t(dm.ltpm),
             center = TRUE,
             scale. = TRUE)

s1 <- summary(m1)
s1
Importance of components:
                           PC1     PC2     PC3      PC4      PC5      PC6      PC7
Standard deviation     66.5041 61.8206 45.2845 30.42909 28.24422 26.84136 25.01865
Proportion of Variance  0.2571  0.2222  0.1192  0.05383  0.04637  0.04188  0.03639
Cumulative Proportion   0.2571  0.4793  0.5985  0.65232  0.69869  0.74058  0.77696
                            PC8      PC9     PC10     PC11    PC12     PC13     PC14
Standard deviation     23.05989 22.08373 21.24391 20.87624 20.6980 20.28169 19.42403
Proportion of Variance  0.03091  0.02835  0.02624  0.02534  0.0249  0.02391  0.02193
Cumulative Proportion   0.80788  0.83623  0.86246  0.88780  0.9127  0.93662  0.95855
                           PC15     PC16      PC17
Standard deviation     19.14803 18.61200 2.085e-13
Proportion of Variance  0.02131  0.02014 0.000e+00
Cumulative Proportion   0.97986  1.00000 1.000e+00

Pareto chart of variance explained by principal components

imp <- data.table(PC = colnames(s1$importance),
                  Variance = 100*s1$importance[2, ],
                  Cumulative = 100*s1$importance[3, ])
imp$PC <- factor(imp$PC,
                 levels = imp$PC)
p1 <- ggplot(imp,
             aes(x = PC,
                 y = Variance)) +
  geom_bar(stat = "identity",
           fill = "grey",
           color = "black") +
  geom_line(aes(y = rescale(Cumulative,
                            to = c(min(Cumulative)*30/100,
                                   30)),
                group = rep(1, nrow(imp)))) +
  geom_point(aes(y = rescale(Cumulative,
                             to = c(min(Cumulative)*30/100,
                                    30)))) +
  scale_y_continuous("% Variance Explained",
                     breaks = seq(0, 30, by = 5),
                     labels = paste(seq(0, 30, by = 5),
                                    "%",
                                    sep = ""),
                     sec.axis = sec_axis(trans = ~.,
                                         name = "% Cumulative Variance",
                                         breaks = seq(0, 30, length.out = 5),
                                         labels = paste(seq(0, 100, length.out = 5),
                                                        "%",
                                                        sep = ""))) +
  scale_x_discrete("") +
  theme(axis.text.x = element_text(angle = 90,
                                   hjust = 1))
print(p1)

# Save for publication
tiff(filename = "tmp/pca_pareto.tiff",
     height = 6,
     width = 8,
     units = 'in',
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()

First 3 principal components, pairwise

# Biplot while keep only the most important variables (Javier)----
# Select PC-s to pliot (PC1 & PC2)
choices <- c(1:3)

# Scores, i.e. points (df.u)
dt.scr <- data.table(m1$x[, choices])
# Add grouping variables
dt.scr$trt <- dmeta$trt
dt.scr$time <- dmeta$time
dt.scr$sample <- dmeta$Sample

# Loadings, i.e. arrows (df.v)
dt.rot <- as.data.frame(m1$rotation[, choices])
dt.rot$feat <- rownames(dt.rot)
dt.rot <- data.table(dt.rot)

# Axis labels
u.axis.labs <- paste(colnames(dt.rot)[choices], 
                     sprintf('(%0.1f%% explained var.)', 
                             100*m1$sdev[choices]^2/sum(m1$sdev^2)))

p1 <- ggplot(data = dt.scr,
             aes(x = PC1,
                 y = PC2,
                 color = trt,
                 shape = time)) +
  geom_point(size = 4,
             alpha = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[2]) +
  theme(legend.position = "none")
ggplotly(p1)


p2 <- ggplot(data = dt.scr,
             aes(x = PC1,
                 y = PC3,
                 color = trt,
                 shape = time)) +
  geom_point(size = 4,
             alpha = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[3]) +
  theme(legend.position = "none")
ggplotly(p2)


p3 <- ggplot(data = dt.scr,
             aes(x = PC2,
                 y = PC3,
                 color = trt,
                 shape = time)) +
  geom_point(size = 4,
             alpha = 0.5) +
  scale_x_continuous(u.axis.labs[2]) +
  scale_y_continuous(u.axis.labs[3]) +
  theme(legend.position = "none")
ggplotly(p3)


# Legend only
tmp <- ggplot(data = dt.scr,
             aes(x = PC1,
                 y = PC2,
                 color = trt,
                 shape = time)) +
  geom_point() +
  scale_color_discrete("Treatment") +
  scale_shape_discrete("Week")
p4 <- as_ggplot(get_legend(tmp))

# Save for publication
tiff(filename = "tmp/pca.tiff",
     height = 7,
     width = 9,
     units = 'in',
     res = 600,
     compression = "lzw+p")
grid.arrange(p1, p2, p3, p4, 
             nrow = 2)
graphics.off()

First 3 principal components, 3D

scatterplot3js(x = dt.scr$PC1, 
               y = dt.scr$PC2, 
               z = dt.scr$PC3, 
               color = as.numeric(dt.scr$trt),
               renderer = "auto",
               pch = dt.scr$sample,
               size = 0.1)

Differential expression analysis (DESeq2 pipeline)

Sources:
1. Analyzing RNA-seq data with DESeq2:Interactions
2. Bioconductor Question: DESeq2 time series analysis
We are testing a model with time*treatment interaction. The idea here is to find genes with significant interaction term. That would suggest that the gene expressiondifferences between the treatments depended on time. THere are several possible scenarios:
a. No difference between the negative control and the positive control groups at baseline, significant difference at the later time point. This will show the effect of the disease (UVB radiation, in this case).
b. Significant difference between the control groups at baseline, no difference at the later time point. Same as (a) above.
c. Differences between the positive control and the SFN-treated groups. Here, we are interested in the reversal of UVB effect. Again, the interaction term will need to be significant for the reasons described above.

# Relevel: make all comparisons with the positive control (UVB)
dmeta$trt <- factor(dmeta$trt,
                    levels = c("UVB",
                               "CON",
                               "SFN"))

dtm<- as.matrix(dt1[, dmeta$Sample,
                    with = FALSE])
rownames(dtm) <- dt1$Geneid

dds <- DESeqDataSetFromMatrix(countData = dtm, 
                              colData = dmeta,
                              ~ time + trt + time:trt)
# If all samples contain zeros, geometric means cannot be
# estimated. Change default 'type = "ratio"' to 'type = "poscounts"'.
# Type '?DESeq2::estimateSizeFactors' for more details.
dds <- estimateSizeFactors(object = dds,
                           type = "poscounts")

# Run DESeq----
dds <- DESeq(object = dds,
             # test = "LRT",
             # reduced = ~ time + trt,
             fitType = "local",
             sfType = "ratio",
             parallel = FALSE)
using pre-existing size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
# NOTE (from DESeq help file, section Value):
# A DESeqDataSet object with results stored as metadata columns. 
# These results should accessed by calling the results function. 
# By default this will return the log2 fold changes and p-values
# for the last variable in the design formula. 
# See results for how to access results for other variables.
# In this case, the last term is the interaction term trt:time

# NOTE: 
# Likelihood ratio test (LRT) (chi-squared test) for GLM will only return 
# the results for the difference between the full and the reduced model

resultsNames(dds)
[1] "Intercept"       "time_15w_vs_02w" "time_25w_vs_02w" "trt_CON_vs_UVB" 
[5] "trt_SFN_vs_UVB"  "time15w.trtCON"  "time25w.trtCON"  "time15w.trtSFN" 
[9] "time25w.trtSFN" 
# Model matrix
mm1 <- model.matrix(~ time + trt + time:trt, dmeta)
mm1
   (Intercept) time15w time25w trtCON trtSFN time15w:trtCON time25w:trtCON
1            1       0       0      1      0              0              0
2            1       0       0      0      1              0              0
3            1       0       0      0      1              0              0
4            1       0       0      0      0              0              0
5            1       0       0      0      0              0              0
6            1       1       0      1      0              1              0
7            1       1       0      1      0              1              0
8            1       1       0      0      1              0              0
9            1       1       0      0      1              0              0
10           1       1       0      0      0              0              0
11           1       1       0      0      0              0              0
12           1       0       1      1      0              0              1
13           1       0       1      1      0              0              1
14           1       0       1      0      1              0              0
15           1       0       1      0      1              0              0
16           1       0       1      0      0              0              0
17           1       0       1      0      0              0              0
   time15w:trtSFN time25w:trtSFN
1               0              0
2               0              0
3               0              0
4               0              0
5               0              0
6               0              0
7               0              0
8               1              0
9               1              0
10              0              0
11              0              0
12              0              0
13              0              0
14              0              1
15              0              1
16              0              0
17              0              0
attr(,"assign")
[1] 0 1 1 2 2 3 3 3 3
attr(,"contrasts")
attr(,"contrasts")$time
[1] "contr.treatment"

attr(,"contrasts")$trt
[1] "contr.treatment"

Results

Effect of UVB at Week 2

res_con_uvb_week2 <- results(dds,
                             contrast = c(0,0,0,1,0,0,0,0,0),
                             alpha = 0.1)
res_con_uvb_week2 <- res_con_uvb_week2[order(res_con_uvb_week2$padj,
                                                   decreasing = FALSE),]
summary(res_con_uvb_week2)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1546, 9%
LFC < 0 (down)     : 1537, 8.9%
outliers [1]       : 0, 0%
low counts [2]     : 2335, 14%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_con_uvb_week2$padj < 0.1, 
    na.rm = TRUE)
[1] 3083
# MA plot
plotMA(res_con_uvb_week2,
             main = "Control vs. UVB at Week 2",
             alpha = 0.8)

# Save for publication
tiff(filename = "tmp/ma_w2_con_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plotMA(res_con_uvb_week2,
             main = "Control vs. UVB at Week 2",
             alpha = 0.8)
graphics.off()

Protective effect of SFN at Week 2

res_sfn_uvb_week2 <- results(dds,
                             contrast = c(0,0,0,0,1,0,0,0,0),
                             alpha = 0.1)
res_sfn_uvb_week2 <- res_sfn_uvb_week2[order(res_sfn_uvb_week2$padj,
                                                   decreasing = FALSE),]
summary(res_sfn_uvb_week2)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 26, 0.15%
LFC < 0 (down)     : 35, 0.2%
outliers [1]       : 0, 0%
low counts [2]     : 3669, 21%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_sfn_uvb_week2$padj < 0.1, 
    na.rm = TRUE)
[1] 61
# MA plot
print(plotMA(res_sfn_uvb_week2,
             main = "UVB+SFN vs UVB at Week 2",
             alpha = 0.8))
NULL
# Save for publication
tiff(filename = "tmp/ma_w2_sfn_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
print(plotMA(res_sfn_uvb_week2,
             main = "UVB+SFN vs UVB at Week 2",
             alpha = 0.8))
NULL
graphics.off()

Genes that were significantly differentiated at both timepoints

lgene.w2.con <- unique(res_con_uvb_week2@rownames[res_con_uvb_week2$padj < 0.1])
lgene.w2.sfn <- unique(res_sfn_uvb_week2@rownames[res_sfn_uvb_week2$padj < 0.1])
lgene.w2 <- lgene.w2.con[lgene.w2.con %in% lgene.w2.sfn]
lgene.w2 <- lgene.w2 [!is.na(lgene.w2 )]
lgene.w2
 [1] "Utrn"    "Stom"    "Tesc"    "Cited4"  "Cdhr1"   "Slc7a11" "Mki67"   "Cyp26b1"
 [9] "Smc2"    "Mad2l1"  "Slc4a7"  "Ankrd23" "Ifitm3"  "Etv3"    "Pla2g4d" "Fetub"  
[17] "Kif11"   "Ccl6"    "Has3"    "Il19"    "A4galt"  "Otud1"   "Msn"     "Nqo1"   
[25] "Dbf4"    "Cblb"    "Tbc1d24" "Elmo2"   "Cd163"   "Esd"     "Rfx2"    "Gsta1"  
[33] "Slurp1"  "Arntl2"  "Vldlr"   "Tmem173" "Gpx2"    "Slfn9"   "Adh7"    "Sprr2i" 
[41] "Bcl2l15"

Plot of DESeq-normalizedcounts of genes significant in both comparisons at Week 2:

# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene.w2)) {
  out <- plotCounts(dds, 
                    gene = lgene.w2[[i]],
                    intgroup = c("trt",
                                 "time"),
                    returnData = TRUE)
  dp1[[i]] <- data.table(Geneid = lgene.w2[[i]],
                         Sample = rownames(out),
                         out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
                  levels = c("CON",
                             "UVB",
                             "SFN"))
dp1$time <- factor(dp1$time,
                   levels = c("02w",
                              "15w",
                              "25w"),
                   labels = c("Week 2",
                              "Week 15",
                              "Week 25"))
dp1$Geneid <- factor(dp1$Geneid,
                     levels = lgene.w2)
dp1[, mu := mean(count,
                 na.rm = TRUE),
    by = c("Geneid",
           "trt",
           "time")]
dmu <- unique(dp1[, -c("Sample",
                       "count")])
head(dmu)
List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

Interactions terms

Tests if the effect of NOT treating with UVB vs. treating with UVB is different at Week 15 compared to Week 2:

res_int_con_uvb_week <- results(dds, 
                                name = "time15w.trtCON",
                                alpha = 0.1)
res_int_con_uvb_week <- res_int_con_uvb_week[order(res_int_con_uvb_week$padj,
                                                   decreasing = FALSE),]
print(res_int_con_uvb_week)
log2 fold change (MLE): time15w.trtCON 
Wald test p-value: time15w.trtCON 
DataFrame with 17202 rows and 6 columns
                  baseMean     log2FoldChange             lfcSE               stat
                 <numeric>          <numeric>         <numeric>          <numeric>
Ces2g     1233.64052107766   1.65919128471462 0.219706072210844   7.55186813008224
Chil4     729.990857182023  -11.1293956873127  1.54858690264879  -7.18680731980641
Tiparp    683.339510901133   1.49955960160452 0.248262587560916   6.04021579061555
Slc25a37  391.064324378349  -1.45460152768479 0.244923011988198  -5.93901534966785
H2-M2      206.94506916379  -1.98012352045144  0.34512732806993  -5.73737099152641
...                    ...                ...               ...                ...
Gpm6b     6.76909966446477  -3.26887203161146  1.55193921192052  -2.10631447836558
Tlr7      1.11233183040672  0.165798521539309  3.90101579949831 0.0425013714532075
Arhgap6   1.55558065988387  0.701543913331167  2.69733929865055   0.26008738080602
Spry3     2.92590454614356 -0.756574618876826     2.19462355565 -0.344740042969577
Zf12     0.240459283234895   1.53995508412402  7.75773006704587  0.198505886491927
                       pvalue                 padj
                    <numeric>            <numeric>
Ces2g    4.29058805762623e-14 5.23408837149824e-10
Chil4    6.63239033912628e-13 4.04542648735007e-09
Tiparp   1.53908254415537e-09 6.25842265205047e-06
Slc25a37  2.8673902141708e-09 8.74482330566741e-06
H2-M2    9.61574727613009e-09 2.34605002043022e-05
...                       ...                  ...
Gpm6b      0.0351770444831032                   NA
Tlr7        0.966099018478313                   NA
Arhgap6     0.794796371714883                   NA
Spry3       0.730289811494176                   NA
Zf12        0.842649279637729                   NA
summary(res_int_con_uvb_week)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 62, 0.36%
LFC < 0 (down)     : 81, 0.47%
outliers [1]       : 0, 0%
low counts [2]     : 5003, 29%
(mean count < 14)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_int_con_uvb_week$padj < 0.1, 
    na.rm = TRUE)
[1] 143
# MA plot
print(plotMA(res_int_con_uvb_week,
             main = "(Control vs. UVB) x TIme Interaction",
             alpha = 0.9))
NULL

Tests if the effect of treating with UVB+SFN vs. treating with UVB is different at Week 15 compared to Week 2:

res_int_sfn_uvb_week <- results(dds, 
                                name = "time15w.trtSFN",
                                alpha = 0.1)
res_int_sfn_uvb_week <- res_int_sfn_uvb_week[order(res_int_sfn_uvb_week$padj,
                                                   decreasing = FALSE),]
print(res_int_sfn_uvb_week)
log2 fold change (MLE): time15w.trtSFN 
Wald test p-value: time15w.trtSFN 
DataFrame with 17202 rows and 6 columns
                  baseMean     log2FoldChange             lfcSE
                 <numeric>          <numeric>         <numeric>
Sprr2i    160.426257994504   2.83987384043744 0.455041717539916
Jakmip2   63.5056363214658   3.21303587147397 0.539789109889979
Ankrd37   235.286753079087   1.69690697674512 0.334405230598706
Rabgap1l  952.654178700566  0.885094830670513 0.193655876057218
Xdh       997.089593301958   1.17874278667067 0.254355414980077
...                    ...                ...               ...
Tex13    0.257950623188226 -0.171416964885152  6.80505378756029
Trpc5os   0.25226659796839  -1.67756077298105  6.85574125799013
Gm6568   0.246930247155146   1.31275277456817  6.92124043267287
Rs1      0.304746600897428  -2.68634965578062   5.6142429285098
Zf12     0.240459283234895  -1.67793188223364  6.93607854502649
                        stat               pvalue                 padj
                   <numeric>            <numeric>            <numeric>
Sprr2i      6.24090875841143 4.35035967805996e-10 7.33818670495154e-06
Jakmip2     5.95239105903574 2.64253030673362e-09 2.22871006069914e-05
Ankrd37     5.07440321345167  3.8871402035267e-07  0.00218560936510295
Rabgap1l     4.5704517140962 4.86674050843135e-06   0.0139492184264559
Xdh         4.63423507914307 3.58259699502912e-06   0.0139492184264559
...                      ...                  ...                  ...
Tex13    -0.0251896561344605    0.979903687548783                   NA
Trpc5os   -0.244694294876708    0.806693145810482                   NA
Gm6568     0.189670159177119    0.849567605832819                   NA
Rs1       -0.478488318013282    0.632302686934451                   NA
Zf12      -0.241913621845704    0.808847094876152                   NA
summary(res_int_sfn_uvb_week)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 11, 0.064%
LFC < 0 (down)     : 2, 0.012%
outliers [1]       : 0, 0%
low counts [2]     : 334, 1.9%
(mean count < 0)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_int_sfn_uvb_week$padj < 0.1, 
    na.rm = TRUE)
[1] 13
# MA plot
print(plotMA(res_int_sfn_uvb_week))
NULL

# NOTE: same as 
# res <- results(dds, 
#                   alpha = 0.05)
# res <- res[order(res$padj, decreasing = FALSE),]
# res

NOTE: By default, the results(dds)* prints the results for the last level of the last term, i.e. here it was for for the interaction term SFN vs. UVB at Week 15 vs. Week 2.

Genes with both interactions being significant

lgene.con <- unique(res_int_con_uvb_week@rownames[res_int_con_uvb_week$padj < 0.1])
lgene.sfn <- unique(res_int_sfn_uvb_week@rownames[res_int_sfn_uvb_week$padj < 0.1])
lgene <- lgene.con[lgene.con %in% lgene.sfn]
lgene <- lgene[!is.na(lgene)]
lgene
[1] "Jakmip2"  "Rabgap1l" "Alox8"    "Xdh"     

Plot of DESeq-normalizedcounts of genes with smallest adjusted p-value for the interaction term:

# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene)) {
  out <- plotCounts(dds, 
                    gene = lgene[[i]],
                    intgroup = c("trt",
                                 "time"),
                    returnData = TRUE)
  dp1[[i]] <- data.table(Geneid = lgene[[i]],
                         Sample = rownames(out),
                         out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
                  levels = c("CON",
                             "UVB",
                             "SFN"))
dp1$time <- factor(dp1$time,
                   levels = c("02w",
                              "15w"),
                   labels = c("Week 2",
                              "Week 15"))
dp1$Geneid <- factor(dp1$Geneid,
                     levels = lgene)
dp1[, mu := mean(count,
                 na.rm = TRUE),
    by = c("Geneid",
           "trt",
           "time")]
dmu <- unique(dp1[, -c("Sample",
                       "count")])

p1 <- ggplot(dp1,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

Compare to the plot of TPM-normalizedcounts of genes with smallest adjusted p-value for the interaction term:

# Examine TPM values for the same genes
tmp <- tpm[Geneid %in% lgene, ]
tmp$Geneid <- factor(tmp$Geneid,
                     levels = lgene)
tmp <- melt.data.table(data = tmp,
                       id.vars = 1,
                       measure.vars = 3:ncol(tmp),
                       variable.name = "Sample",
                       value.name = "TPM")
tmp <- merge(dmeta,
             tmp,
             by = "Sample")

p1 <- ggplot(tmp,
             aes(x = Week,
                 y = TPM,
                 fill = Treatment,
                 group = Treatment)) +
  facet_wrap(~ Geneid,
             scales = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black")+
  scale_x_discrete("")
plot(p1)

Session Information

sessionInfo()
LS0tDQp0aXRsZTogIlNraW4gVVZCIFNLSDEgbW91c2UgbW9kZWwgdHJlYXRlZCB3aXRoIFNGTiAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KLS0tDQoNCiMgUGFydCAxOiBSTkENCmBgYHtyIGhlYWRlciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGVycm9yID0gRkFMU0UsIHdhcm5pbmcgID1GQUxTRX0NCiMgaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkNCiMgICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikNCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoIkRFU2VxMiIpDQoNCnJlcXVpcmUoa25pdHIpDQpyZXF1aXJlKGRhdGEudGFibGUpDQpyZXF1aXJlKERUKQ0KcmVxdWlyZShERVNlcTIpDQpyZXF1aXJlKHJlYWR4bCkNCnJlcXVpcmUoQmlvY1BhcmFsbGVsKQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShwbG90bHkpDQpyZXF1aXJlKHRocmVlanMpDQpyZXF1aXJlKHNjYWxlcykNCnJlcXVpcmUoZ3JpZEV4dHJhKQ0KcmVxdWlyZShnZ3B1YnIpDQoNCiMgTk9URTogb24gREVTZXEyIE91dHB1dDogJ2Jhc2VNZWFuJyBpcyB0aGUgYXZlcmFnZSBvZiB0aGUgbm9ybWFsaXplZCBjb3VudCB2YWx1ZXMsIA0KIyBkaXZpZGVkIGJ5IHRoZSBzaXplIGZhY3RvcnMsIHRha2VuIG92ZXIgYWxsIHNhbXBsZXMgaW4gdGhlIERFU2VxRGF0YVNldA0KYGBgDQoNCiMjIExvYWQgUk5BIHNhbXBsZXMNCk91dCBvZiAzMCBzYW1wbGVzLCB3ZSBzZWxlY3RlZCAxNyBmb3IgdGhpcyBzdHVkeS4gVGhlc2UgYXJlIHRoZSBub3JtYWwgdGlzc3VlIHNhbXBsZXMgZm9ybSB0aGUgY29udHJvbCwgdGhlIFVWQSBhbmQgdGhlIFVWQStTRk4gdHJlYXRtZW50IGdyb3Vwcy4gbm9ybWFsIHRpc3N1ZSBzYW1wbGVzIGZyb20gdGhlIFVWQl9VQSBncm91cHMgYXMgd2VsbCBhcyB0dW1vciBzYW1wbGVzIHdlcmUgZXhjbHVkZWQgZnJvbSB0aGlzIGFuYWx5c2lzLiBBZGRpdGlvbmFsbHksIG9uZSBvZiB0aGUgY29udHJvbCBzYW1wbGVzIGF0IFdlZWsgMiAoYmFzZWxpbmUpIHdhcyByZW1vdmVkIGFmdGVyIG91dGxpZXIgYW5hbHlzaXMuICAgIA0KNywyMTkgZ2VuZXMgd2l0aCB6ZXJvIGNvdW50cyBpbiA+IDgwJSAoPiAxMyBvdXQgb2YgMTgpIG9mIHNhbXBsZXMgd2VyZSByZW1vdmVkLiAxNywyMDIgb3V0IG9mIDI0LDQyMSBnZW5lcyB3ZXJlIGxlZnQuIA0KICAgICAgICAgDQpgYGB7ciBkYXRhX3JuYSwgd2FybmluZyA9IEZBTFNFLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0NCiMgTG9hZCBkYXRhLS0tLQ0KZHQwIDwtIGZyZWFkKCJkYXRhL3JlbnlpX2RlZHVwX3JuYXNlcV9kYXRhL2ZlYXR1cmVzY291bnRzX3V2Yi1za2luX2RlZHVwX3JlbnlpXzItOS0yMDE4LmNzdiIsDQogICAgICAgICAgICAgc2tpcCA9IDEpDQoNCiMgUmVtb3ZlIHVudXNlZCBjb2x1bW5zLS0tLQ0KZHQxIDwtIGR0MFssIGMoMSwgNjpuY29sKGR0MCkpLCB3aXRoID0gRkFMU0VdDQoNCmNuYW1lcyA8LSBjb2xuYW1lcyhkdDEpWy1jKDE6MildDQpjbmFtZXMgPC0gZ3N1Yih4ID0gY25hbWVzLA0KICAgICAgICAgICAgICAgcGF0dGVybiA9ICIuZGVkdXAuYmFtIiwNCiAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIiIpDQpjb2xuYW1lcyhkdDEpWy1jKDE6MildIDwtIGNuYW1lcw0KDQojIEFUVEVOVElPTiEgSW4gdGhpcyBhbmFseXNpcywgd2Ugd2lsbCBvbmx5IGV4YW1pbmUgY29udHJvbHMgYW5kIFNGTg0KIyBBbHNvLCByZW1vdmVkIGNhbmNlciBjZWxsIHNhbXBsZXMNCnRuYW1lcyA8LSBzdWJzdHIoeCA9IGNvbG5hbWVzKGR0MSksIA0KICAgICAgICAgICAgICAgICBzdGFydCA9IDMsDQogICAgICAgICAgICAgICAgIHN0b3AgPSAzKQ0KDQpnbmFtZXMgPC0gc3Vic3RyKHggPSBjb2xuYW1lcyhkdDEpLCANCiAgICAgICAgICAgICAgICAgc3RhcnQgPSA1LA0KICAgICAgICAgICAgICAgICBzdG9wID0gNykNCg0KZHQxIDwtIGR0MVssIGduYW1lcyAlaW4lIGMoImlkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiQ09OIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIgKSAmDQogICAgICAgICAgICAgdG5hbWVzICE9ICJ0IiwNCiAgICAgICAgICAgd2l0aCA9IEZBTFNFXQ0KIyAxOCBzYW1wbGVzIGxlZnQNCg0KIyBSZW1vdmUgc2FtcGxlICcwMndfQ09OXzEnIGFzIGFuIG91dGxpZXINCiMgU2VlICdza2luX3V2Yl9zZm5fZXhjbHVkZV9jb24ydzFfdjEnIGZvciBkZXRhaWxzDQpkdDEgPC0gZHQxWywgY29sbmFtZXMoZHQxKSAhPSAiMDJ3X0NPTl8xIiwgd2l0aCA9IEZBTFNFXQ0KDQojIFJlbW92ZSBnZW5lcyB3aXRoIHplcm8gY291bnRzIGluID4gODAlICg+IDEzIG91dCBvZiAxNykgb2Ygc2FtcGxlcw0KdG1wIDwtIGR0MVssIC1jKDE6MildID09IDANCnRtcCA8LSByb3dTdW1zKHRtcCkgPiAxMw0Kc3VtKHRtcCkNCg0KZHQxIDwtIGRyb3BsZXZlbHMoZHQxWyF0bXAsIF0pDQpucm93KGR0MSkNCiMgMTcsMjAyIG91dCBvZiAyNCw0MjEgZ2VuZXMgbGVmdA0KDQpkYXRhdGFibGUoaGVhZChkdDEsIDEwKSwNCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLA0KICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCksDQogICAgICAgICAgY2FwdGlvbiA9ICJUYWJsZSAxOiBmaXJzdCAxMCByb3dzIG9mIHRoZSBjb3VudCB0YWJsZSIpDQpgYGANCg0KIyMgVHJhbnNjcmlwdHMgcGVyIGtpbG9iYXNlIG1pbGxpb24gKFRQTSkgbm9ybWFsaXphdGlvbg0KTmV4dCwgd2Ugbm9yYW1pemVkIHRoZSBjb3VudHMuIFRvIGNvbnZlcnQgbnVtYmVyIG9mIGhpdHMgdG8gIHRoZSByZWxhdGl2ZSBhYnVuZGFuZSBvZiBnZW5lcyBpbiBlYWNoIHNhbXBsZSwgd2UgdXNlZCAqKip0cmFuc2NyaXB0cyBwZXIga2lsb2Jhc2UgbWlsbGlvbiAoVFBNKSoqKiBub3JtYWxpemF0aW9uLCB3aGljaCBpcyBhcyBmb2xsb3dpbmcgZm9yIHRoZSBqLXRoIHNhbXBsZTogICAgICAgDQoxLiBub3JtaWxpemUgZm9yIGdlbmUgbGVuZ3RoOiBhW2ksIGpdID0gMSwwMDAqY291bnRbaSwgal0vZ2VuZVtpLCBqXSBsZW5ndGgoYnApICAgICANCjIuIG5vcm1hbGl6ZSBmb3Igc2VxIGRlcHRoIChpLmUuIHRvdGFsIGNvdW50KTogYShpLCBqKS9zdW0oYVssIGpdKSAgICAgDQozLiBtdWx0aXBseSBieSBvbmUgbWlsbGlvbiAgICAgDQpBIHZlcnkgZ29vZCBjb21wYXJpc29uIG9mIG5vcm1hbGl6YXRpb24gdGVjaG5pcXVlcyBjYW4gYmUgZm91bmQgYXQgdGhlIGZvbGxvd2luZyB2aWRlbzogICAgDQpbUlBLTSwgRlBLTSBhbmQgVFBNLCBjbGVhcmx5IGV4cGxhaW5lZF0oaHR0cHM6Ly93d3cucm5hLXNlcWJsb2cuY29tL3Jwa20tZnBrbS1hbmQtdHBtLWNsZWFybHktZXhwbGFpbmVkLykNCiAgICAgDQpBZnRlciB0aGUgbm9ybWFsaXphdGlvbiwgZWFjaCBzYW1wbGUncyB0b3RhbCBpcyAxTToNCiAgICAgDQpgYGB7ciB0cG0sIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQojIE5vcm1hbGl6ZSBjb3VudHMgdG8gVFBNDQp0bXAgPC0gMTAwMCpkdDFbLCAzOm5jb2woZHQxKV0vZHQxJExlbmd0aA0KdHBtIDwtIGRhdGEudGFibGUoR2VuZWlkID0gZHQxJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgIExlbmd0aCA9IGR0MSRMZW5ndGgsDQogICAgICAgICAgICAgICAgICBhcHBseSh0bXAsDQogICAgICAgICAgICAgICAgICAgICAgICAyLA0KICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oYSkgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAxMF42KihhL3N1bShhKSkNCiAgICAgICAgICAgICAgICAgICAgICAgIH0pKQ0KY29sU3Vtcyh0cG1bLCAtYygxOjIpXSkNCg0KZm9ybWF0Um91bmQoZGF0YXRhYmxlKGhlYWQodHBtLCAxMCksDQogICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApLA0KICAgICAgICAgICAgICAgICAgICAgIGNhcHRpb24gPSAiVGFibGUgMjogdHJhbnNjcmlwdHMgcGVyIGtpbG9iYXNlIG1pbGxpb24gKFRQTSkgbm9ybWFsaXplZCBjb3VudHMiKSwNCiAgICAgICAgICAgIGNvbHVtbnMgPSAzOm5jb2wodHBtKSwNCiAgICAgICAgICAgIGRpZ2l0cyA9IDIpDQoNCiMgVG90YWwgVFBNDQp0b3RhbCA8LSByb3dTdW1zKHRwbVssIDM6bmNvbCh0cG0pXSkNCg0KIyBTb3J0IGdlbmVzIGJ5IHJlbGF0aXZlIGFidW5kYW5jeQ0KdHBtJEdlbmVpZCA8LSBmYWN0b3IodHBtJEdlbmVpZCAsDQogICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB0cG0kR2VuZWlkW29yZGVyKHRvdGFsLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gRkFMU0UpXSkNCmBgYA0KDQojIFRvcCAxMDAgbW9zdCBhYnVuZGFudCBSTkEgbW9sZWN1bGVzDQpgYGB7ciBtb3N0X2FidW5kYW50fQ0KIyBTZXBhcmF0ZSB0b3AgMTAwIGFidW5kYW50IGdlbmVzDQp0bXAgPC0gZHJvcGxldmVscyh0cG1bR2VuZWlkICVpbiUgbGV2ZWxzKHRwbSRHZW5laWQpWyhucm93KHRwbSkgLSA5OSk6bnJvdyh0cG0pXV0pDQoNCnRtcCA8LSBtZWx0LmRhdGEudGFibGUoZGF0YSA9IHRtcCwNCiAgICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IDE6MiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMzpuY29sKHRtcCksDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiU2FtcGxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJUUE0iKQ0KDQp0bXAkV2VlayA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgc3RhcnQgPSAxLA0KICAgICAgICAgICAgICAgICAgIHN0b3AgPSAzKQ0KdG1wJFdlZWsgPC0gZmFjdG9yKHRtcCRXZWVrLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHVuaXF1ZSh0bXAkV2VlaykpDQoNCg0KdG1wJFRyZWF0bWVudCA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gNykNCnRtcCRUcmVhdG1lbnQgPC0gZmFjdG9yKHRtcCRUcmVhdG1lbnQsDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iKSkNCg0KdG1wJFJlcGxpY2EgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gOSwNCiAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gOSkNCnRtcCRSZXBsaWNhIDwtIGZhY3Rvcih0bXAkUmVwbGljYSwNCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSAwOjEpDQoNCiMgUGxvdCB0b3AgMTAwIGFidW5kYW50IGdlbmVzDQpwMiA8LSBnZ3Bsb3QodG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gVFBNLA0KICAgICAgICAgICAgICAgICB5ID0gR2VuZWlkLA0KICAgICAgICAgICAgICAgICBmaWxsID0gVHJlYXRtZW50LA0KICAgICAgICAgICAgICAgICBzaGFwZSA9IFdlZWspKSArDQogICMgZmFjZXRfd3JhcCh+IFNleCwgbnJvdyA9IDEpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpDQpnZ3Bsb3RseShwMikNCmBgYA0KDQojIEJvdHRvbSAxMDAgbGVhc3QgYWJ1bmRhbnQgUk5BIG1vbGVjdWxlcw0KYGBge3IgbGVhc3RfYWJ1bmRhbnR9DQp0bXAgPC0gZHJvcGxldmVscyh0cG1bR2VuZWlkICVpbiUgbGV2ZWxzKHRwbSRHZW5laWQpWzE6MTAwXV0pDQoNCnRtcCA8LSBtZWx0LmRhdGEudGFibGUoZGF0YSA9IHRtcCwNCiAgICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IDE6MiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMzpuY29sKHRtcCksDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiU2FtcGxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJUUE0iKQ0KDQp0bXAkV2VlayA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgc3RhcnQgPSAxLA0KICAgICAgICAgICAgICAgICAgIHN0b3AgPSAzKQ0KdG1wJFdlZWsgPC0gZmFjdG9yKHRtcCRXZWVrLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHVuaXF1ZSh0bXAkV2VlaykpDQoNCg0KdG1wJFRyZWF0bWVudCA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gNykNCnRtcCRUcmVhdG1lbnQgPC0gZmFjdG9yKHRtcCRUcmVhdG1lbnQsDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iKSkNCg0KdG1wJFJlcGxpY2EgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gOSwNCiAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gOSkNCnRtcCRSZXBsaWNhIDwtIGZhY3Rvcih0bXAkUmVwbGljYSwNCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSAwOjEpDQoNCiMgUGxvdCB0b3AgMTAwIGFidW5kYW50IGdlbmVzDQpwMyA8LSBnZ3Bsb3QodG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gVFBNLA0KICAgICAgICAgICAgICAgICB5ID0gR2VuZWlkLA0KICAgICAgICAgICAgICAgICBmaWxsID0gVHJlYXRtZW50LA0KICAgICAgICAgICAgICAgICBzaGFwZSA9IFdlZWspKSArDQogICMgZmFjZXRfd3JhcCh+IFNleCwgbnJvdyA9IDEpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpDQpnZ3Bsb3RseShwMykNCmBgYA0KDQojIE1ldGEgZGF0YQ0KYGBge3IgbWV0YX0NCmRtZXRhIDwtIGRhdGEudGFibGUoU2FtcGxlID0gY29sbmFtZXMoZHQxKVstYygxOjIpXSkNCg0KZG1ldGEkdGltZSA8LSBzdWJzdHIoeCA9IGRtZXRhJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMSwNCiAgICAgICAgICAgICAgICAgICAgIHN0b3AgPSAzKQ0KZG1ldGEkdGltZSA8LSBmYWN0b3IoZG1ldGEkdGltZSwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxNXciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjV3IikpDQpkbWV0YSRXZWVrIDwtIGZhY3RvcihkbWV0YSR0aW1lLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiMDJ3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjE1dyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNXciKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldlZWsgMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDE1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlZWsgMjUiKSkNCg0KZG1ldGEkdHJ0IDwtIHN1YnN0cih4ID0gZG1ldGEkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDUsDQogICAgICAgICAgICAgICAgICAgIHN0b3AgPSA3KQ0KZG1ldGEkdHJ0IDwtIGZhY3RvcihkbWV0YSR0cnQsDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNPTiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iKSkNCmRtZXRhJFRyZWF0bWVudCA8LSBmYWN0b3IoZG1ldGEkdHJ0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk5lZ2F0aXZlIENvbnRyb2wiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb3NpdGl2ZSBDb250cm9sIChVVkIpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3VsZm9yYXBoYW5lIChTRk4pIikpDQoNCmRtZXRhJFJlcGxpY2EgPC0gc3Vic3RyKHggPSBkbWV0YSRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDksDQogICAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gOSkNCmRtZXRhJFJlcGxpY2EgPC0gZmFjdG9yKGRtZXRhJFJlcGxpY2EsDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSAwOjEpDQoNCmRhdGF0YWJsZShkbWV0YSwNCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gbnJvdyhkbWV0YSkpKQ0KYGBgDQoNCiMgUENBIG9mIFRQTQ0KTk9URTogdGhlIGRpc3RyaWJ1dGlvbnMgYXJlIHNrZXdlZC4gVG8gbWFrZSB0aGVtIHN5bW1ldHJpYywgbG9nIHRyYW5zZm9ybWF0aW9uIGlzIG9mdGVuIGFwcGxpZWQuIEhvd2V2ZXIsIHRoZXJlIGlzIGFuIGlzc3VlIG9mIHplcm9zLiBJbiB0aGlzIGluc3RhbmNlLCB3ZSBhZGRlZCBhIHNtYWxsIHZhbHVlcyAqKipsYW1iZGFbaV0qKiogZXF1YWwgdG8gMS8xMCBvZiB0aGUgc21hbGxlc3Qgbm9uLXplcm8gdmFsdWUgb2YgKmkqLXRoIGdlbmUuIA0KYGBge3IgcGNhfQ0KZG0udHBtIDwtIGFzLm1hdHJpeCh0cG1bLCAtYygxOjIpLCB3aXRoID0gRkFMU0VdKQ0Kcm93bmFtZXMoZG0udHBtKSA8LSB0cG0kR2VuZWlkDQoNCiMgIyBSZW1vdmUgMDJ3X0NPTl8xIHNhbXBsZSBhbmQgcmVkbyBQQ0ENCiMgZG0udHBtIDwtIGRtLnRwbVssIGNvbG5hbWVzKGRtLnRwbSkgIT0gIjAyd19DT05fMSJdDQojIGRtZXRhIDwtIGRtZXRhW2RtZXRhJFNhbXBsZSAhPSAiMDJ3X0NPTl8xIiwgXQ0KDQojIEFkZCBsYW1iZGFzIHRvIGFsbCB2YWx1ZXMsIHRoZW4gdGFrZSBhIGxvZw0KZG0ubHRwbSA8LSB0KGFwcGx5KFggPSBkbS50cG0sDQogICAgICAgICAgICAgICAgICAgICAgTUFSR0lOID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbihhKSB7DQogICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgPC0gbWluKGFbYSA+IDBdKS8xMA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nKGEgKyBsYW1iZGEpDQogICAgICAgICAgICAgICAgICAgICAgfSkpDQoNCiMgUENBLS0tLQ0KbTEgPC0gcHJjb21wKHQoZG0ubHRwbSksDQogICAgICAgICAgICAgY2VudGVyID0gVFJVRSwNCiAgICAgICAgICAgICBzY2FsZS4gPSBUUlVFKQ0KDQpzMSA8LSBzdW1tYXJ5KG0xKQ0KczENCmBgYA0KDQojIFBhcmV0byBjaGFydCBvZiB2YXJpYW5jZSBleHBsYWluZWQgYnkgcHJpbmNpcGFsIGNvbXBvbmVudHMNCmBgYHtyIHBjYV92YXJfcGxvdH0NCmltcCA8LSBkYXRhLnRhYmxlKFBDID0gY29sbmFtZXMoczEkaW1wb3J0YW5jZSksDQogICAgICAgICAgICAgICAgICBWYXJpYW5jZSA9IDEwMCpzMSRpbXBvcnRhbmNlWzIsIF0sDQogICAgICAgICAgICAgICAgICBDdW11bGF0aXZlID0gMTAwKnMxJGltcG9ydGFuY2VbMywgXSkNCmltcCRQQyA8LSBmYWN0b3IoaW1wJFBDLA0KICAgICAgICAgICAgICAgICBsZXZlbHMgPSBpbXAkUEMpDQpwMSA8LSBnZ3Bsb3QoaW1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMsDQogICAgICAgICAgICAgICAgIHkgPSBWYXJpYW5jZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsDQogICAgICAgICAgIGZpbGwgPSAiZ3JleSIsDQogICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSByZXNjYWxlKEN1bXVsYXRpdmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSBjKG1pbihDdW11bGF0aXZlKSozMC8xMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDMwKSksDQogICAgICAgICAgICAgICAgZ3JvdXAgPSByZXAoMSwgbnJvdyhpbXApKSkpICsNCiAgZ2VvbV9wb2ludChhZXMoeSA9IHJlc2NhbGUoQ3VtdWxhdGl2ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSBjKG1pbihDdW11bGF0aXZlKSozMC8xMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAzMCkpKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIiUgVmFyaWFuY2UgRXhwbGFpbmVkIiwNCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAzMCwgYnkgPSA1KSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHBhc3RlKHNlcSgwLCAzMCwgYnkgPSA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKSwNCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXModHJhbnMgPSB+LiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIlIEN1bXVsYXRpdmUgVmFyaWFuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMzAsIGxlbmd0aC5vdXQgPSA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gcGFzdGUoc2VxKDAsIDEwMCwgbGVuZ3RoLm91dCA9IDUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiJSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKSkpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKQ0KcHJpbnQocDEpDQoNCiMgU2F2ZSBmb3IgcHVibGljYXRpb24NCnRpZmYoZmlsZW5hbWUgPSAidG1wL3BjYV9wYXJldG8udGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gOCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnByaW50KHAxKQ0KZ3JhcGhpY3Mub2ZmKCkNCmBgYA0KDQojIEZpcnN0IDMgcHJpbmNpcGFsIGNvbXBvbmVudHMsIHBhaXJ3aXNlDQpgYGB7ciBwY2FfcGxvdHN9DQojIEJpcGxvdCB3aGlsZSBrZWVwIG9ubHkgdGhlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlcyAoSmF2aWVyKS0tLS0NCiMgU2VsZWN0IFBDLXMgdG8gcGxpb3QgKFBDMSAmIFBDMikNCmNob2ljZXMgPC0gYygxOjMpDQoNCiMgU2NvcmVzLCBpLmUuIHBvaW50cyAoZGYudSkNCmR0LnNjciA8LSBkYXRhLnRhYmxlKG0xJHhbLCBjaG9pY2VzXSkNCiMgQWRkIGdyb3VwaW5nIHZhcmlhYmxlcw0KZHQuc2NyJHRydCA8LSBkbWV0YSR0cnQNCmR0LnNjciR0aW1lIDwtIGRtZXRhJHRpbWUNCmR0LnNjciRzYW1wbGUgPC0gZG1ldGEkU2FtcGxlDQoNCiMgTG9hZGluZ3MsIGkuZS4gYXJyb3dzIChkZi52KQ0KZHQucm90IDwtIGFzLmRhdGEuZnJhbWUobTEkcm90YXRpb25bLCBjaG9pY2VzXSkNCmR0LnJvdCRmZWF0IDwtIHJvd25hbWVzKGR0LnJvdCkNCmR0LnJvdCA8LSBkYXRhLnRhYmxlKGR0LnJvdCkNCg0KIyBBeGlzIGxhYmVscw0KdS5heGlzLmxhYnMgPC0gcGFzdGUoY29sbmFtZXMoZHQucm90KVtjaG9pY2VzXSwgDQogICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCcoJTAuMWYlJSBleHBsYWluZWQgdmFyLiknLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwKm0xJHNkZXZbY2hvaWNlc11eMi9zdW0obTEkc2Rldl4yKSkpDQoNCnAxIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMxLA0KICAgICAgICAgICAgICAgICB5ID0gUEMyLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1sxXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMl0pICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dwbG90bHkocDEpDQoNCnAyIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMxLA0KICAgICAgICAgICAgICAgICB5ID0gUEMzLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1sxXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbM10pICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dwbG90bHkocDIpDQoNCnAzIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMyLA0KICAgICAgICAgICAgICAgICB5ID0gUEMzLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1syXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbM10pICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dwbG90bHkocDMpDQoNCiMgTGVnZW5kIG9ubHkNCnRtcCA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnNjciwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDMSwNCiAgICAgICAgICAgICAgICAgeSA9IFBDMiwNCiAgICAgICAgICAgICAgICAgY29sb3IgPSB0cnQsDQogICAgICAgICAgICAgICAgIHNoYXBlID0gdGltZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfY29sb3JfZGlzY3JldGUoIlRyZWF0bWVudCIpICsNCiAgc2NhbGVfc2hhcGVfZGlzY3JldGUoIldlZWsiKQ0KcDQgPC0gYXNfZ2dwbG90KGdldF9sZWdlbmQodG1wKSkNCg0KIyBTYXZlIGZvciBwdWJsaWNhdGlvbg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvcGNhLnRpZmYiLA0KICAgICBoZWlnaHQgPSA3LA0KICAgICB3aWR0aCA9IDksDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpncmlkLmFycmFuZ2UocDEsIHAyLCBwMywgcDQsIA0KICAgICAgICAgICAgIG5yb3cgPSAyKQ0KZ3JhcGhpY3Mub2ZmKCkNCmBgYA0KDQojIEZpcnN0IDMgcHJpbmNpcGFsIGNvbXBvbmVudHMsIDNEDQpgYGB7ciBwY2FfM2QsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9DQpzY2F0dGVycGxvdDNqcyh4ID0gZHQuc2NyJFBDMSwgDQogICAgICAgICAgICAgICB5ID0gZHQuc2NyJFBDMiwgDQogICAgICAgICAgICAgICB6ID0gZHQuc2NyJFBDMywgDQogICAgICAgICAgICAgICBjb2xvciA9IGFzLm51bWVyaWMoZHQuc2NyJHRydCksDQogICAgICAgICAgICAgICByZW5kZXJlciA9ICJhdXRvIiwNCiAgICAgICAgICAgICAgIHBjaCA9IGR0LnNjciRzYW1wbGUsDQogICAgICAgICAgICAgICBzaXplID0gMC4xKQ0KYGBgDQoNCiMgRGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgKERFU2VxMiBwaXBlbGluZSkNClNvdXJjZXM6ICAgIA0KMS4gW0FuYWx5emluZyBSTkEtc2VxIGRhdGEgd2l0aCBERVNlcTI6SW50ZXJhY3Rpb25zXShodHRwczovL3d3dy5iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL2RldmVsL2Jpb2MvdmlnbmV0dGVzL0RFU2VxMi9pbnN0L2RvYy9ERVNlcTIuaHRtbCNpbnRlcmFjdGlvbnMpICAgICANCjIuIFtCaW9jb25kdWN0b3IgUXVlc3Rpb246IERFU2VxMiB0aW1lIHNlcmllcyBhbmFseXNpc10oaHR0cHM6Ly9zdXBwb3J0LmJpb2NvbmR1Y3Rvci5vcmcvcC85NzQzMC8pICAgICAgDQpXZSBhcmUgdGVzdGluZyBhIG1vZGVsIHdpdGggdGltZSp0cmVhdG1lbnQgaW50ZXJhY3Rpb24uIFRoZSBpZGVhIGhlcmUgaXMgdG8gZmluZCBnZW5lcyB3aXRoIHNpZ25pZmljYW50IGludGVyYWN0aW9uIHRlcm0uIFRoYXQgd291bGQgc3VnZ2VzdCB0aGF0IHRoZSBnZW5lIGV4cHJlc3Npb25kaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSB0cmVhdG1lbnRzIGRlcGVuZGVkIG9uIHRpbWUuIFRIZXJlIGFyZSBzZXZlcmFsIHBvc3NpYmxlIHNjZW5hcmlvczogICAgDQphLiBObyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG5lZ2F0aXZlIGNvbnRyb2wgYW5kIHRoZSBwb3NpdGl2ZSBjb250cm9sIGdyb3VwcyBhdCBiYXNlbGluZSwgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBhdCB0aGUgbGF0ZXIgdGltZSBwb2ludC4gVGhpcyB3aWxsIHNob3cgdGhlIGVmZmVjdCBvZiB0aGUgZGlzZWFzZSAoVVZCIHJhZGlhdGlvbiwgaW4gdGhpcyBjYXNlKS4gICAgIA0KYi4gU2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBjb250cm9sIGdyb3VwcyBhdCBiYXNlbGluZSwgbm8gZGlmZmVyZW5jZSBhdCB0aGUgbGF0ZXIgdGltZSBwb2ludC4gU2FtZSBhcyAoYSkgYWJvdmUuICAgICANCmMuIERpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHBvc2l0aXZlIGNvbnRyb2wgYW5kIHRoZSBTRk4tdHJlYXRlZCBncm91cHMuIEhlcmUsIHdlIGFyZSBpbnRlcmVzdGVkIGluIHRoZSByZXZlcnNhbCBvZiBVVkIgZWZmZWN0LiBBZ2FpbiwgdGhlIGludGVyYWN0aW9uIHRlcm0gd2lsbCBuZWVkIHRvIGJlIHNpZ25pZmljYW50IGZvciB0aGUgcmVhc29ucyBkZXNjcmliZWQgYWJvdmUuICAgICAgDQoNCmBgYHtyIGRlc2VxMn0NCiMgUmVsZXZlbDogbWFrZSBhbGwgY29tcGFyaXNvbnMgd2l0aCB0aGUgcG9zaXRpdmUgY29udHJvbCAoVVZCKQ0KZG1ldGEkdHJ0IDwtIGZhY3RvcihkbWV0YSR0cnQsDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KDQpkdG08LSBhcy5tYXRyaXgoZHQxWywgZG1ldGEkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICB3aXRoID0gRkFMU0VdKQ0Kcm93bmFtZXMoZHRtKSA8LSBkdDEkR2VuZWlkDQoNCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGR0bSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gZG1ldGEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IHRpbWUgKyB0cnQgKyB0aW1lOnRydCkNCiMgSWYgYWxsIHNhbXBsZXMgY29udGFpbiB6ZXJvcywgZ2VvbWV0cmljIG1lYW5zIGNhbm5vdCBiZQ0KIyBlc3RpbWF0ZWQuIENoYW5nZSBkZWZhdWx0ICd0eXBlID0gInJhdGlvIicgdG8gJ3R5cGUgPSAicG9zY291bnRzIicuDQojIFR5cGUgJz9ERVNlcTI6OmVzdGltYXRlU2l6ZUZhY3RvcnMnIGZvciBtb3JlIGRldGFpbHMuDQpkZHMgPC0gZXN0aW1hdGVTaXplRmFjdG9ycyhvYmplY3QgPSBkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBvc2NvdW50cyIpDQoNCiMgUnVuIERFU2VxLS0tLQ0KZGRzIDwtIERFU2VxKG9iamVjdCA9IGRkcywNCiAgICAgICAgICAgICAjIHRlc3QgPSAiTFJUIiwNCiAgICAgICAgICAgICAjIHJlZHVjZWQgPSB+IHRpbWUgKyB0cnQsDQogICAgICAgICAgICAgZml0VHlwZSA9ICJsb2NhbCIsDQogICAgICAgICAgICAgc2ZUeXBlID0gInJhdGlvIiwNCiAgICAgICAgICAgICBwYXJhbGxlbCA9IEZBTFNFKQ0KDQojIE5PVEUgKGZyb20gREVTZXEgaGVscCBmaWxlLCBzZWN0aW9uIFZhbHVlKToNCiMgQSBERVNlcURhdGFTZXQgb2JqZWN0IHdpdGggcmVzdWx0cyBzdG9yZWQgYXMgbWV0YWRhdGEgY29sdW1ucy4gDQojIFRoZXNlIHJlc3VsdHMgc2hvdWxkIGFjY2Vzc2VkIGJ5IGNhbGxpbmcgdGhlIHJlc3VsdHMgZnVuY3Rpb24uIA0KIyBCeSBkZWZhdWx0IHRoaXMgd2lsbCByZXR1cm4gdGhlIGxvZzIgZm9sZCBjaGFuZ2VzIGFuZCBwLXZhbHVlcw0KIyBmb3IgdGhlIGxhc3QgdmFyaWFibGUgaW4gdGhlIGRlc2lnbiBmb3JtdWxhLiANCiMgU2VlIHJlc3VsdHMgZm9yIGhvdyB0byBhY2Nlc3MgcmVzdWx0cyBmb3Igb3RoZXIgdmFyaWFibGVzLg0KIyBJbiB0aGlzIGNhc2UsIHRoZSBsYXN0IHRlcm0gaXMgdGhlIGludGVyYWN0aW9uIHRlcm0gdHJ0OnRpbWUNCg0KIyBOT1RFOiANCiMgTGlrZWxpaG9vZCByYXRpbyB0ZXN0IChMUlQpIChjaGktc3F1YXJlZCB0ZXN0KSBmb3IgR0xNIHdpbGwgb25seSByZXR1cm4gDQojIHRoZSByZXN1bHRzIGZvciB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBmdWxsIGFuZCB0aGUgcmVkdWNlZCBtb2RlbA0KDQpyZXN1bHRzTmFtZXMoZGRzKQ0KDQojIE1vZGVsIG1hdHJpeA0KbW0xIDwtIG1vZGVsLm1hdHJpeCh+IHRpbWUgKyB0cnQgKyB0aW1lOnRydCwgZG1ldGEpDQptbTENCmBgYA0KDQojIFJlc3VsdHMNCiMjIEVmZmVjdCBvZiBVVkIgYXQgV2VlayAyDQpgYGB7ciBkZXNlcTJfcmVzdWx0c193ZWVrMl9jb25fdXZifQ0KcmVzX2Nvbl91dmJfd2VlazIgPC0gcmVzdWx0cyhkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gYygwLDAsMCwxLDAsMCwwLDAsMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KcmVzX2Nvbl91dmJfd2VlazIgPC0gcmVzX2Nvbl91dmJfd2VlazJbb3JkZXIocmVzX2Nvbl91dmJfd2VlazIkcGFkaiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSksXQ0Kc3VtbWFyeShyZXNfY29uX3V2Yl93ZWVrMikNCg0KIyBIb3cgbWFueSBhZGp1c3RlZCBwLXZhbHVlcyB3ZXJlIGxlc3MgdGhhbiAwLjA1Pw0Kc3VtKHJlc19jb25fdXZiX3dlZWsyJHBhZGogPCAwLjEsIA0KICAgIG5hLnJtID0gVFJVRSkNCg0KIyBNQSBwbG90DQpwbG90TUEocmVzX2Nvbl91dmJfd2VlazIsDQogICAgICAgICAgICAgbWFpbiA9ICJDb250cm9sIHZzLiBVVkIgYXQgV2VlayAyIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkNCg0KIyBTYXZlIGZvciBwdWJsaWNhdGlvbg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvbWFfdzJfY29uX3V2Yi50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNiwNCiAgICAgd2lkdGggPSA3LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcGxvdE1BKHJlc19jb25fdXZiX3dlZWsyLA0KICAgICAgICAgICAgIG1haW4gPSAiQ29udHJvbCB2cy4gVVZCIGF0IFdlZWsgMiIsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjgpDQpncmFwaGljcy5vZmYoKQ0KYGBgDQoNCiMjIFByb3RlY3RpdmUgZWZmZWN0IG9mIFNGTiBhdCBXZWVrIDINCmBgYHtyIGRlc2VxMl9yZXN1bHRzX3dlZWsyX3Nmbl91dmJ9DQpyZXNfc2ZuX3V2Yl93ZWVrMiA8LSByZXN1bHRzKGRkcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKDAsMCwwLDAsMSwwLDAsMCwwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjEpDQpyZXNfc2ZuX3V2Yl93ZWVrMiA8LSByZXNfc2ZuX3V2Yl93ZWVrMltvcmRlcihyZXNfc2ZuX3V2Yl93ZWVrMiRwYWRqLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKSxdDQpzdW1tYXJ5KHJlc19zZm5fdXZiX3dlZWsyKQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMDU/DQpzdW0ocmVzX3Nmbl91dmJfd2VlazIkcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KDQojIE1BIHBsb3QNCnByaW50KHBsb3RNQShyZXNfc2ZuX3V2Yl93ZWVrMiwNCiAgICAgICAgICAgICBtYWluID0gIlVWQitTRk4gdnMgVVZCIGF0IFdlZWsgMiIsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjgpKQ0KDQojIFNhdmUgZm9yIHB1YmxpY2F0aW9uDQp0aWZmKGZpbGVuYW1lID0gInRtcC9tYV93Ml9zZm5fdXZiLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDcsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwcmludChwbG90TUEocmVzX3Nmbl91dmJfd2VlazIsDQogICAgICAgICAgICAgbWFpbiA9ICJVVkIrU0ZOIHZzIFVWQiBhdCBXZWVrIDIiLA0KICAgICAgICAgICAgIGFscGhhID0gMC44KSkNCmdyYXBoaWNzLm9mZigpDQpgYGANCg0KIyMgR2VuZXMgdGhhdCB3ZXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWF0ZWQgYXQgYm90aCB0aW1lcG9pbnRzDQpgYGB7ciBzaWduX3cyfQ0KbGdlbmUudzIuY29uIDwtIHVuaXF1ZShyZXNfY29uX3V2Yl93ZWVrMkByb3duYW1lc1tyZXNfY29uX3V2Yl93ZWVrMiRwYWRqIDwgMC4xXSkNCmxnZW5lLncyLnNmbiA8LSB1bmlxdWUocmVzX3Nmbl91dmJfd2VlazJAcm93bmFtZXNbcmVzX3Nmbl91dmJfd2VlazIkcGFkaiA8IDAuMV0pDQpsZ2VuZS53MiA8LSBsZ2VuZS53Mi5jb25bbGdlbmUudzIuY29uICVpbiUgbGdlbmUudzIuc2ZuXQ0KbGdlbmUudzIgPC0gbGdlbmUudzIgWyFpcy5uYShsZ2VuZS53MiApXQ0KbGdlbmUudzINCmBgYA0KDQpQbG90IG9mIERFU2VxLW5vcm1hbGl6ZWRjb3VudHMgb2YgZ2VuZXMgc2lnbmlmaWNhbnQgaW4gYm90aCBjb21wYXJpc29ucyBhdCBXZWVrIDI6ICAgDQoNCmBgYHtyIGRlc2VxMl93MnNpZ25fZGVzZXFub3JtfQ0KIyBHZXQgdGhlIERFU2VxLW5vcm1hbGl6ZSBjb3VudHMNCmRwMSA8LSBsaXN0KCkNCmZvciAoaSBpbiAxOmxlbmd0aChsZ2VuZS53MikpIHsNCiAgb3V0IDwtIHBsb3RDb3VudHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IGxnZW5lLncyW1tpXV0sDQogICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gYygidHJ0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aW1lIiksDQogICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBUUlVFKQ0KICBkcDFbW2ldXSA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IGxnZW5lLncyW1tpXV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgU2FtcGxlID0gcm93bmFtZXMob3V0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvdXQpDQp9DQpkcDEgPC0gcmJpbmRsaXN0KGRwMSkNCmRwMSR0cnQgPC0gZmFjdG9yKGRwMSR0cnQsDQogICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KZHAxJHRpbWUgPC0gZmFjdG9yKGRwMSR0aW1lLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTV3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNXciKSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXZWVrIDIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlZWsgMTUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlZWsgMjUiKSkNCmRwMSRHZW5laWQgPC0gZmFjdG9yKGRwMSRHZW5laWQsDQogICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBsZ2VuZS53MikNCmRwMVssIG11IDo9IG1lYW4oY291bnQsDQogICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksDQogICAgYnkgPSBjKCJHZW5laWQiLA0KICAgICAgICAgICAidHJ0IiwNCiAgICAgICAgICAgInRpbWUiKV0NCmRtdSA8LSB1bmlxdWUoZHAxWywgLWMoIlNhbXBsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICJjb3VudCIpXSkNCmhlYWQoZG11KQ0KYGBgDQoNCmBgYHtyIGRlc2VxMl93MnNpZ25fZGVzZXFub3JtX3cycGxvdCwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA4fQ0KZG11LncyIDwtIGRtdVt0aW1lID09ICJXZWVrIDIiLCBdDQpkbXUudzJbLCBkbi51cCA6PSAobXVbdHJ0ID09ICJVVkIiXSA8IG11W3RydCA9PSAiQ09OIl0pICYNCiAgICAgICAgICAgICAgIChtdVt0cnQgPT0gIlVWQiJdIDwgbXVbdHJ0ID09ICJTRk4iXSksDQogICAgICAgYnkgPSBHZW5laWRdDQpkbXUudzJbLCB1cC5kbiA6PSAobXVbdHJ0ID09ICJVVkIiXSA+IG11W3RydCA9PSAiQ09OIl0pICYNCiAgICAgICAgICAgICAgIChtdVt0cnQgPT0gIlVWQiJdID4gbXVbdHJ0ID09ICJTRk4iXSksDQogICAgICAgYnkgPSBHZW5laWRdDQpwMSA8LSBnZ3Bsb3QoZG11LncyW3VwLmRuID09IFRSVUUsIF0sDQogICAgICAgICAgICAgYWVzKHggPSB0cnQsDQogICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBHZW5laWQsDQogICAgICAgICAgICAgICAgIGZpbGwgPSB0cnQpKSArDQogICAgICAgIGZhY2V0X3dyYXAofiBHZW5laWQsDQogICAgICAgICAgICAgICAgICAgc2NhbGUgPSAiZnJlZV95IikgKw0KICAgICAgICBnZW9tX2xpbmUocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpKSArDQogICAgICAgIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEsDQogICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMsDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArDQogICAgICAgIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKCJEaWZmZXJlbnRpYWxseSBFeHByZXNzZWQgR2VuZXMgYXQgV2VlayAyIikgKw0KICAgICAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKSArDQogICAgICAgIGdndGl0bGUoIkdlbmVzIFVwcmVndWxhdGVkIGJ5IFVWQiIpDQp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkNCnAxDQojIHRpZmYoZmlsZW5hbWUgPSAidG1wL3cyX3VwX2RuLnRpZmYiLA0KIyAgICAgIGhlaWdodCA9IDYsDQojICAgICAgd2lkdGggPSA4LA0KIyAgICAgIHVuaXRzID0gJ2luJywNCiMgICAgICByZXMgPSAzMDAsDQojICAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KIyBwcmludChwMSkNCiMgZ3JhcGhpY3Mub2ZmKCkNCg0KcDIgPC0gZ2dwbG90KGRtdS53Mltkbi51cCA9PSBUUlVFLCBdLA0KICAgICAgICAgICAgIGFlcyh4ID0gdHJ0LA0KICAgICAgICAgICAgICAgICB5ID0gbXUsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gR2VuZWlkLA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICAgICAgICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgICAgICAgZ2VvbV9saW5lKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSkgKw0KICAgICAgICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSwNCiAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxLA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSAzLA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKw0KICAgICAgICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogICAgICAgIHNjYWxlX3lfY29udGludW91cygiRGlmZmVyZW50aWFsbHkgRXhwcmVzc2VkIEdlbmVzIGF0IFdlZWsgMiIpICsNCiAgICAgICAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiVHJlYXRtZW50IikgKw0KICAgICAgICBnZ3RpdGxlKCJHZW5lcyBEb3ducmVndWxhdGVkIGJ5IFVWQiIpDQp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkNCnAyDQojIHRpZmYoZmlsZW5hbWUgPSAidG1wL3cyX2RuX3VwLnRpZmYiLA0KIyAgICAgIGhlaWdodCA9IDYsDQojICAgICAgd2lkdGggPSA4LA0KIyAgICAgIHVuaXRzID0gJ2luJywNCiMgICAgICByZXMgPSAzMDAsDQojICAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KIyBwcmludChwMikNCiMgZ3JhcGhpY3Mub2ZmKCkNCmBgYA0KDQojIyBEaWQgdGhlc2UgdHJlbmRzIHBlcnNpc3RlZD8NCmBgYHtyIGRlc2VxMl93MnNpZ25fZGVzZXFub3JtX3Bsb3RfYWxsX3VwX2RuLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEyfQ0KZHAxLnRtcCA8LSBkcDFbZHAxJEdlbmVpZCAlaW4lIHVuaXF1ZShkbXUudzIkR2VuZWlkW2RtdS53MiR1cC5kbl0pLCBdDQpkbXUudG1wIDwtIGRtdVtkbXUkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MiRHZW5laWRbZG11LncyJHVwLmRuXSksIF0NCnAxIDwtIGdncGxvdChkcDEudG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwNCiAgICAgICAgICAgICAgICAgeSA9IGNvdW50LA0KICAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IHRydCkpICsNCiAgZmFjZXRfd3JhcCh+IEdlbmVpZCwNCiAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3kiKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgIHNoYXBlID0gMjEsDQogICAgICAgICAgICAgc2l6ZSA9IDUsDQogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fbGluZShkYXRhID0gZG11LnRtcCwNCiAgICAgICAgICAgIGFlcyh4ID0gdGltZSwNCiAgICAgICAgICAgICAgICB5ID0gbXUsDQogICAgICAgICAgICAgICAgZ3JvdXAgPSB0cnQsDQogICAgICAgICAgICAgICAgY29sb3VyID0gdHJ0KSwNCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSwNCiAgICAgICAgICAgIGFscGhhID0gMC41LA0KICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIkRFU2VxLU5vcm1hbGl6ZWQgQ291bnRzIikgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKQ0KcHJpbnQocDEpDQpgYGANCg0KYGBge3IgZGVzZXEyX3cyc2lnbl9kZXNlcW5vcm1fcGxvdF9hbGxfZG5fdXAsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTJ9DQpkcDEudG1wIDwtIGRwMVtkcDEkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MiRHZW5laWRbZG11LncyJGRuLnVwXSksIF0NCmRtdS50bXAgPC0gZG11W2RtdSRHZW5laWQgJWluJSB1bmlxdWUoZG11LncyJEdlbmVpZFtkbXUudzIkZG4udXBdKSwgXQ0KcDEgPC0gZ2dwbG90KGRwMS50bXAsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUudG1wLA0KICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSB0cnQpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgYWxwaGEgPSAwLjUsDQogICAgICAgICAgICBzaXplID0gMikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogIHNjYWxlX3lfY29udGludW91cygiREVTZXEtTm9ybWFsaXplZCBDb3VudHMiKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIlRyZWF0bWVudCIpDQpwcmludChwMSkNCmBgYA0KDQpJbiBtYW55IG9mIHRoZXNlIGdlbmVzLCBVVkIrU0ZOIG1vdmVkIGNsb3NlciB0byBVVkIgb3ZlciB0aW1lLg0KDQojIyBJbnRlcmFjdGlvbnMgdGVybXMNClRlc3RzIGlmIHRoZSBlZmZlY3Qgb2YgTk9UIHRyZWF0aW5nIHdpdGggVVZCIHZzLiB0cmVhdGluZyB3aXRoIFVWQiBpcyBkaWZmZXJlbnQgYXQgV2VlayAxNSBjb21wYXJlZCB0byBXZWVrIDI6ICAgIA0KYGBge3IgZGVzZXEyX3dlZWsyX3dlZWsxNV9yZXN1bHRzX2ludF9jb25fdXZifQ0KcmVzX2ludF9jb25fdXZiX3dlZWsgPC0gcmVzdWx0cyhkZHMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gInRpbWUxNXcudHJ0Q09OIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjEpDQpyZXNfaW50X2Nvbl91dmJfd2VlayA8LSByZXNfaW50X2Nvbl91dmJfd2Vla1tvcmRlcihyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKSxdDQpwcmludChyZXNfaW50X2Nvbl91dmJfd2VlaykNCnN1bW1hcnkocmVzX2ludF9jb25fdXZiX3dlZWspDQoNCiMgSG93IG1hbnkgYWRqdXN0ZWQgcC12YWx1ZXMgd2VyZSBsZXNzIHRoYW4gMC4wNT8NCnN1bShyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqIDwgMC4xLCANCiAgICBuYS5ybSA9IFRSVUUpDQoNCiMgTUEgcGxvdA0KcHJpbnQocGxvdE1BKHJlc19pbnRfY29uX3V2Yl93ZWVrLA0KICAgICAgICAgICAgIG1haW4gPSAiKENvbnRyb2wgdnMuIFVWQikgeCBUSW1lIEludGVyYWN0aW9uIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOSkpDQoNCmBgYA0KDQpUZXN0cyBpZiB0aGUgZWZmZWN0IG9mIHRyZWF0aW5nIHdpdGggVVZCK1NGTiB2cy4gdHJlYXRpbmcgd2l0aCBVVkIgaXMgZGlmZmVyZW50IGF0IFdlZWsgMTUgY29tcGFyZWQgdG8gV2VlayAyOiAgICANCmBgYHtyIGRlc2VxMl93ZWVrMl93ZWVrMTVfcmVzdWx0c19pbnRfc2ZuX3V2Yn0NCnJlc19pbnRfc2ZuX3V2Yl93ZWVrIDwtIHJlc3VsdHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJ0aW1lMTV3LnRydFNGTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KcmVzX2ludF9zZm5fdXZiX3dlZWsgPC0gcmVzX2ludF9zZm5fdXZiX3dlZWtbb3JkZXIocmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSksXQ0KcHJpbnQocmVzX2ludF9zZm5fdXZiX3dlZWspDQpzdW1tYXJ5KHJlc19pbnRfc2ZuX3V2Yl93ZWVrKQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMDU/DQpzdW0ocmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KDQojIE1BIHBsb3QNCnByaW50KHBsb3RNQShyZXNfaW50X3Nmbl91dmJfd2VlaykpDQoNCiMgTk9URTogc2FtZSBhcyANCiMgcmVzIDwtIHJlc3VsdHMoZGRzLCANCiMgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1KQ0KIyByZXMgPC0gcmVzW29yZGVyKHJlcyRwYWRqLCBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCiMgcmVzDQpgYGANCg0KKipOT1RFKio6IEJ5IGRlZmF1bHQsIHRoZSAqKnJlc3VsdHMoZGRzKSoqKiBwcmludHMgdGhlIHJlc3VsdHMgZm9yIHRoZSBsYXN0IGxldmVsIG9mIHRoZSBsYXN0IHRlcm0sIGkuZS4gaGVyZSBpdCB3YXMgZm9yIGZvciB0aGUgaW50ZXJhY3Rpb24gdGVybSBTRk4gdnMuIFVWQiBhdCBXZWVrIDE1IHZzLiBXZWVrIDIuDQogICAgICAgDQojIEdlbmVzIHdpdGggYm90aCBpbnRlcmFjdGlvbnMgYmVpbmcgc2lnbmlmaWNhbnQNCmBgYHtyIHNpZ25faW50fQ0KbGdlbmUuY29uIDwtIHVuaXF1ZShyZXNfaW50X2Nvbl91dmJfd2Vla0Byb3duYW1lc1tyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqIDwgMC4xXSkNCmxnZW5lLnNmbiA8LSB1bmlxdWUocmVzX2ludF9zZm5fdXZiX3dlZWtAcm93bmFtZXNbcmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiA8IDAuMV0pDQpsZ2VuZSA8LSBsZ2VuZS5jb25bbGdlbmUuY29uICVpbiUgbGdlbmUuc2ZuXQ0KbGdlbmUgPC0gbGdlbmVbIWlzLm5hKGxnZW5lKV0NCmxnZW5lDQpgYGANCg0KICAgICAgIA0KUGxvdCBvZiBERVNlcS1ub3JtYWxpemVkY291bnRzIG9mIGdlbmVzIHdpdGggc21hbGxlc3QgYWRqdXN0ZWQgcC12YWx1ZSBmb3IgdGhlIGludGVyYWN0aW9uIHRlcm06ICAgICANCmBgYHtyIGRlc2VxMl93ZWVrMl93ZWVrMTVfdG9wOV9kZXNlcW5vcm0sIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA4fQ0KIyBHZXQgdGhlIERFU2VxLW5vcm1hbGl6ZSBjb3VudHMNCmRwMSA8LSBsaXN0KCkNCmZvciAoaSBpbiAxOmxlbmd0aChsZ2VuZSkpIHsNCiAgb3V0IDwtIHBsb3RDb3VudHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IGxnZW5lW1tpXV0sDQogICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gYygidHJ0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aW1lIiksDQogICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBUUlVFKQ0KICBkcDFbW2ldXSA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IGxnZW5lW1tpXV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgU2FtcGxlID0gcm93bmFtZXMob3V0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvdXQpDQp9DQpkcDEgPC0gcmJpbmRsaXN0KGRwMSkNCmRwMSR0cnQgPC0gZmFjdG9yKGRwMSR0cnQsDQogICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KZHAxJHRpbWUgPC0gZmFjdG9yKGRwMSR0aW1lLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTV3IiksDQogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2VlayAyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDE1IikpDQpkcDEkR2VuZWlkIDwtIGZhY3RvcihkcDEkR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbGdlbmUpDQpkcDFbLCBtdSA6PSBtZWFuKGNvdW50LA0KICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLA0KICAgIGJ5ID0gYygiR2VuZWlkIiwNCiAgICAgICAgICAgInRydCIsDQogICAgICAgICAgICJ0aW1lIildDQpkbXUgPC0gdW5pcXVlKGRwMVssIC1jKCJTYW1wbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAiY291bnQiKV0pDQoNCnAxIDwtIGdncGxvdChkcDEsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUsDQogICAgICAgICAgICBhZXMoeCA9IHRpbWUsDQogICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgIGNvbG91ciA9IHRydCksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICBhbHBoYSA9IDAuNSwNCiAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJERVNlcS1Ob3JtYWxpemVkIENvdW50cyIpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiVHJlYXRtZW50IikNCnByaW50KHAxKQ0KYGBgDQogICAgICANCkNvbXBhcmUgdG8gdGhlIHBsb3Qgb2YgVFBNLW5vcm1hbGl6ZWRjb3VudHMgb2YgZ2VuZXMgd2l0aCBzbWFsbGVzdCBhZGp1c3RlZCBwLXZhbHVlIGZvciB0aGUgaW50ZXJhY3Rpb24gdGVybTogICAgIA0KYGBge3IgZGVzZXEyX3dlZWsyX3dlZWsxNV90cG1ub3JtLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0NCiMgRXhhbWluZSBUUE0gdmFsdWVzIGZvciB0aGUgc2FtZSBnZW5lcw0KdG1wIDwtIHRwbVtHZW5laWQgJWluJSBsZ2VuZSwgXQ0KdG1wJEdlbmVpZCA8LSBmYWN0b3IodG1wJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxnZW5lKQ0KdG1wIDwtIG1lbHQuZGF0YS50YWJsZShkYXRhID0gdG1wLA0KICAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMzpuY29sKHRtcCksDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiU2FtcGxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJUUE0iKQ0KdG1wIDwtIG1lcmdlKGRtZXRhLA0KICAgICAgICAgICAgIHRtcCwNCiAgICAgICAgICAgICBieSA9ICJTYW1wbGUiKQ0KDQpwMSA8LSBnZ3Bsb3QodG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gV2VlaywNCiAgICAgICAgICAgICAgICAgeSA9IFRQTSwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBUcmVhdG1lbnQpKSArDQogIGZhY2V0X3dyYXAofiBHZW5laWQsDQogICAgICAgICAgICAgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKQ0KcGxvdChwMSkNCmBgYA0KDQojIFNlc3Npb24gSW5mb3JtYXRpb24NCmBgYHtyIGluZm8sZXZhbD1UUlVFfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBg